#include "common.h"
#include "filesystem.h"
#include "../../std/string.h"
#include "../../std/path.h"
#include "../../std/errno.h"
#include "../driver/ata.h"
#include "isr.h"

File fileTable[MAX_FILES];
char sectorsList[MAX_SECTOR_BYTES] = {0};
File * currentDir;
File root;
char currentPath[MAX_PATH]="\0";

char userName[NAME_MAX_LENGTH];
char groupName[NAME_MAX_LENGTH];

File * getParentDir(char * path);
void saveTable();
void loadHeaderFromDisk(int sector, File* file);
void saveHeaderOnDisk(File * file, int new);
File * getChild(File * file, char * name);
File * getFileByPath(File * file, char * path);
void initFileTable();
void sys_add_enode(File *  directory,char * new_file_name, unsigned int child_sector);

/*Devuelde el directorio actual*/
File * getCurrentDir(){
        return currentDir;
}

/*Devuelve el path del directorio actual*/
char * getPath(){
	
	return currentPath;
}

/*Setea el sector como libre*/
void clearSector(int sector){
        char bit = sector%8;
        sectorsList[sector/8] &= ~(1 << bit);
        return;
}

int sectorPresent(int sector){
        char bit = sector%8;
        return sectorsList[sector/8] & (1<<bit);
}

/*Setea el sector pasado como parametro como ocupado*/
void setSector(int sector){
        char bit = sector%8;
        sectorsList[sector/8] |= 1 << bit;
        return;
}

/*Devuelve un sector libre de la tabla de sectores*/
int getFileFreeSector(){
        int i;
        for(i=FILETABLE_SECTOR_START;i<MAX_SECTORS;i++){
                if(!sectorPresent(i)){
			setSector(i);
			saveTable();
                        return i;
		}
	}
        return -1;
}

/*Copia informacion de un archivo, de origin a dest*/
void copyFile(File * dest, File * origin){

	strcpy(dest->name, origin->name);
	strcpy(dest->owner, origin->owner);
	dest->sector=origin->sector;
	dest->psector=origin->psector;
	dest->sectorRefData=origin->sectorRefData;
	dest->type=origin->type;	
	dest->count=origin->count;	
	dest->mode=origin->mode;
	dest->parent=origin->parent;	
}

/*Se limpia toda la tabla de sectores*/
void initSectorTable(){
	
		
        int i;

        for(i=0;i<MAX_SECTORS;i++)
                clearSector(i);
}

/*Se escribe el header y bitmap de los sectores - Se protegen los primeros sectores del disco*/
void createFilesystem(){
	
	int i;
        initSectorTable();
	
	//Primer espacio en disco protegido
        for(i=0;i<TABLE_STARTUP_SECTOR;i++)
                setSector(i);

	//Tabla de sectores protegida
        for(i=TABLE_STARTUP_SECTOR;i<TABLE_STARTUP_SECTOR+TABLE_SECTOR_SIZE;i++)
                setSector(i);
	
	saveTable();
	initFileTable();	
	
        writeDisk(ATA0, TABLE_HEADER, strlen(TABLE_HEADER), TABLE_STARTUP_SECTOR, 0);
	
}

/*Se levanta el directorio root y se lo setea como directorio actual*/
void loadFileTable(){
        int i;
        for(i=0;i<MAX_FILES;i++)
                fileTable[i].sector = -1;
               
	loadHeaderFromDisk(FILETABLE_SECTOR_START, &fileTable[0]);
        currentDir=fileTable;
	strcpy(currentDir->name, FILE_ROOT);
	copyFile(&root, currentDir);
}

/*Devuelve una posicion de la tabla de archivos libre*/
int getFreeFileIndex(){
	int i;
	for(i=0;i<MAX_FILES;i++)
		if(fileTable[i].sector == -1){
			return i;
			
		}
	return -1;
}

/*Devuelve un archivo libre de la tabla de archivos*/
File * getFreeFile(){
	int i;
	for(i=0;i<MAX_FILES;i++)
		if(fileTable[i].sector == -1){
			return &fileTable[i];
			
		}
	return NULL;
}

/*Se setea un sector como vacio*/
void setEmpty(int sector){
	unsigned int cero=0;
	writeDisk(ATA0, &cero, sizeof(unsigned int), sector, 0);
}

/*Pregunta si se tiene los permisos "perm" para el archivo "file"
perm: READ_PERMISSION | WRITE_PERMISSION | EXE_PERMISSION*/

int hasPermission(File * file, int perm){
	
	unsigned int mode[3];
	unsigned int fileMode=file->mode;
	int i;
	for(i=2; i>=0;i--){
		mode[i]=fileMode % 10;
		fileMode /= 10;
	}
	int user;
	/*Si el usuario es el dueño*/
	if(strcmp(file->owner, userName) == 0 ){
		user=OWNER;
	}
	/*No es el dueño pero es del grupo*/
	else if(strcmp(file->group, groupName) == 0 ){
		user=GROUP;
	}
	/*No es el dueño y no pertenece al grupo*/
	else{
		user=OTHER;
	}
	return (mode[user] & perm);
	
}



/*Se fija si el RfData esta lleno*/
int RefDataFull(RefData refData){
	
	unsigned int cant;
	readDisk(ATA0, &cant, sizeof(unsigned int),refData.sector+refData.sectorCant-1,0);
	if(cant<ENODE_CANT){
		return 0;
	}
	return 1;
}

/*Agrega un nuevo nodo.
directory: Directorio padre.
new_file_name: El nombre del nuevo nodo.
child_sector: el sector donde se encuentra el nuevo archivo*/

void sys_add_enode(File *  directory,char * new_file_name, unsigned int child_sector){
	RefDataSector refDataSector;
	unsigned int sector=directory->sectorRefData;
	
	readDisk(ATA0, &refDataSector, sizeof(RefDataSector), sector, 0);
	while(refDataSector.cant>=REF_DATA_CANT){
		sector=refDataSector.next;
		readDisk(ATA0, &refDataSector, sizeof(RefDataSector), sector, 0);
	}
	
	if(refDataSector.cant==0 || RefDataFull(refDataSector.list[refDataSector.cant-1])){

		refDataSector.cant++;
		if(refDataSector.cant==REF_DATA_CANT){
			int new_refData_sector=getFileFreeSector();
			refDataSector.next=new_refData_sector;
			writeDisk(ATA0, &refDataSector, sizeof(RefDataSector), sector, 0);
			sector=new_refData_sector;
			refDataSector.cant=1;
		}
		int new_dirData_sector=getFileFreeSector();	

		refDataSector.list[refDataSector.cant-1].sector=new_dirData_sector;
		refDataSector.list[refDataSector.cant-1].sectorCant=1;
		
		writeDisk(ATA0, &refDataSector, sizeof(RefDataSector), sector, 0);

		setEmpty(new_dirData_sector);
		
		readDisk(ATA0, &refDataSector, sizeof(RefDataSector), sector, 0);
		
	}
	
	
	RefData refData=refDataSector.list[refDataSector.cant-1];
	
	DirData dirData;
	
	readDisk(ATA0, &dirData, sizeof(DirData), refData.sector+refData.sectorCant-1, 0);
	
	strcpy(dirData.list[dirData.eNodeCant].name,new_file_name);
	
	dirData.list[dirData.eNodeCant].sector=child_sector;
	dirData.eNodeCant++;
	
	writeDisk(ATA0, &dirData, sizeof(DirData), refData.sector+refData.sectorCant-1, 0);
	
}

/*Le agrega al directorio "file", los nodos "." y ".." con su referencia correspondiente*/
void initDirData(File * file){

	sys_add_enode(file,".",file->sector);
	sys_add_enode(file,"..",file->psector);

}


/*Se crea un nuevo archivo
psector: el sector donde se encuentra el archivo padre
mode: los permisos del nuevo archivo
type: el tipo de archivo. DIRECTORY_TYPE | FILE_TYPE | FIFO_TYPE*/
File * createFile(int psector, short int mode, unsigned int type){
	
	
	
  	File * f = getFreeFile();

	strcpy(f->owner, userName);
	strcpy(f->group, groupName);

	int sectorHeader = getFileFreeSector();
	f->sector = sectorHeader;
	
	if(type!=FIFO_TYPE){
		int sectorRefData = getFileFreeSector();
		f->sectorRefData = sectorRefData;
	}
	else{
		f->sectorRefData=0;
	}
 	f->size = 128;
 	f->mode = mode;
 	f->type = type;
 	f->count = 1;
	f->psector = (psector == -1)? f->sector : psector;
	
	
	saveHeaderOnDisk(f,1);
	
	return f;
}


/*Se guarda en disco el mapbit de sectores libres y usados*/
void saveTable(){
	
        writeDisk(ATA0,  sectorsList,MAX_SECTOR_BYTES, TABLE_STARTUP_SECTOR,strlen(TABLE_HEADER));
}

/*Carga en "file" la cabecera del archivo que se encuentra en el sector "sector"*/
void loadHeaderFromDisk(int sector,File* file){
  
 // 	printk("LOAD-----------------------------------------------\n");      
	setSector(sector);

        int sectors = /*(file->size / 512) +*/ 1;
        int i;
        for(i=0;i<sectors;i++)
                setSector(sector);

        //saveTable();
	File_Disk fileDisk;
	
        readDisk(ATA0, &fileDisk, sizeof(File_Disk),sector, 0);
	strcpy(file->group, fileDisk.group);
	strcpy(file->owner, fileDisk.owner);
	file->sectorRefData = fileDisk.sectorRefData;
	file->count = fileDisk.count;
	file->size = fileDisk.size;
	file->mode = fileDisk.mode;
	file->type = fileDisk.type;
	file->sector=sector;	
}

/*Guarda la cabecera de  "file" en el sectorRefData del file. El segundo paramtro dice si es un archivo nuevo o no */
void saveHeaderOnDisk(File * file,int new){
	
        if(new){
		setEmpty(file->sectorRefData);		
	}

        int i;

	File_Disk fileDisk;
	strcpy(fileDisk.group ,file->group);
	strcpy(fileDisk.owner, file->owner);
	fileDisk.sectorRefData = file->sectorRefData;
	fileDisk.count = file->count;
	fileDisk.size = file->size;
	fileDisk.mode = file->mode;
	fileDisk.type = file->type;
	
	
        writeDisk(ATA0, &fileDisk, sizeof(File_Disk), file->sector, 0);
}

/*Devuelve el archivo "name" que se encuentra en el directorio actual*/
File * getCurrentChild(char * name){
        return getChild(currentDir, name);
}


/*Crea el directorio raiz "root" y el directorio ".info" donde luego se guerdara informacion del sistema (como los users)*/
void initFileTable(){
	int i;
	for(i=0;i<MAX_FILES;i++)
		fileTable[i].sector = -1;
	
	File * newRoot;
	newRoot = createFile( -1, 755, DIRECTORY_TYPE);
	
	strcpy(newRoot->name, FILE_ROOT);
	currentDir = newRoot;	
	
	initDirData(newRoot);
	copyFile(&root, newRoot);
	
	mknode("/.info", 770, DIRECTORY_TYPE);
		
}

/*Devuelve el archivo de nombre "name" ubicado en el directorio "file"*/
File * getChild(File * file, char * name){
	
	
	if(file->type != DIRECTORY_TYPE)
		return NULL;

	RefDataSector refDataSector;
	
	
	readDisk(ATA0, &refDataSector, sizeof(RefDataSector), file->sectorRefData, 0);
	
//	int index = getFreeFileIndex();
	DirData dirData;
	RefData refData;
	int i, j, k;
	for(i=0; i < refDataSector.cant; i++){
		if(i == REF_DATA_CANT -1){
			readDisk(ATA0, &refDataSector, sizeof(RefDataSector), refDataSector.next, 0);
			i=-1;
		}
		else{
			refData=refDataSector.list[i];
			for(j=0; j < refData.sectorCant; j++){
				readDisk(ATA0, &dirData, sizeof(DirData), refData.sector + j, 0);
				for(k=0; k<dirData.eNodeCant; k++){
					if(strcmp(name, dirData.list[k].name) == 0){
						loadHeaderFromDisk(dirData.list[k].sector,&fileTable[1]);
						strcpy(fileTable[1].name, name);						
						return &fileTable[1];
					}
				}
				
			}
		}
	}
	return NULL;
}

/*Helper de getFileByPath*/
File * _getFileByPath(File * file, char * path){
	
	
	if( file == NULL ){
		return	NULL;
	}
	
	if( isLastNode(path) ){
		return	getChild(file, path);
	}

	
	char next[FILE_NAME];
	char cola[MAX_PATH];
	getFirstNode(next, path);
	getCola(cola, path);
	
	
	return _getFileByPath(getChild(file, next), cola);
	
}

/*Devuelve el archivo correspondiente al path. Para esto se le pasa el directorio y el path. Si el path es absoluto se llama a la funcion helper el directorio root y el path, sino se le pasa el directorio recivido y el path*/
File * getFileByPath(File * file, char * path){
	
	
	if(strcmp(path, "/")==0)
		return _getFileByPath(&root, ".");
	
	
	if(isAbsolutePath(path)){
		return _getFileByPath(&root, path+1);
	}
	else
		return _getFileByPath(file, path);
		
	
}

/*Recive un path y devuelve el directorio padre del archivo correspondiente al path*/
File * getParentDir(char * path){ 
	
	File * parentDir;
	
	if(isLastNode(path)){
		
		parentDir=currentDir;		
	}
	else{
		char parentPath[MAX_PATH];
		withoutLastNode(parentPath, path);
		parentDir = getFileByPath(currentDir, parentPath);
	}
	
	return parentDir;
	
}

/*Remueve el ultimo nodo del directorio "directory" y carga la informacion del mismo en "lastENode"*/
void popLastENode( eNode * lastENode, File * directory){
	
	RefDataSector refDataSector;
	int sector=directory->sectorRefData;
	int previo=directory->sectorRefData;
	readDisk(ATA0, &refDataSector, sizeof(RefDataSector), sector, 0);
	while(refDataSector.cant>=REF_DATA_CANT){
		previo=sector;
		sector=refDataSector.next;
		readDisk(ATA0, &refDataSector, sizeof(RefDataSector), sector, 0);
	}
	
	RefData refData = refDataSector.list[refDataSector.cant-1];
	DirData dirData;
	readDisk(ATA0, &dirData, sizeof(DirData), refData.sector + (refData.sectorCant -1), 0);
						
	strcpy(lastENode->name,dirData.list[dirData.eNodeCant-1].name);
	lastENode->sector=(dirData.list[dirData.eNodeCant-1]).sector;
	
	dirData.eNodeCant -= 1;
	writeDisk(ATA0, &dirData.eNodeCant, sizeof(unsigned int), refData.sector + (refData.sectorCant -1), 0);
	
	if(dirData.eNodeCant == 0){
		refDataSector.cant -= 1;			
		if(refDataSector.cant == 0){
			readDisk(ATA0, &refDataSector, sizeof(RefDataSector), previo, 0);
			sector=previo;
		}
		writeDisk(ATA0, &refDataSector, sizeof(RefDataSector), sector, 0);
	}
}

/*Remueve el inodo del directoio "dir" con nombre "name"*/
void deleteENode(File * dir, char * name){
	
	RefDataSector refDataSector;
	readDisk(ATA0, &refDataSector, sizeof(RefDataSector), dir->sectorRefData, 0);
	
	DirData dirData;
	RefData refData;
	int i, j, k;
	for(i=0; i < refDataSector.cant; i++){
		if(i == REF_DATA_CANT -1){
			readDisk(ATA0, &refDataSector, sizeof(RefDataSector), refDataSector.next, 0);
			i=-1;
		}
		else{
			refData=refDataSector.list[i];
			for(j=0; j < refData.sectorCant; j++){
				readDisk(ATA0, &dirData, sizeof(DirData), refData.sector + j, 0);
				for(k=0; k<dirData.eNodeCant; k++){
					if(strcmp(name, dirData.list[k].name) == 0){
						eNode lastENode;
						popLastENode(&lastENode, dir);
						strcpy(dirData.list[k].name, lastENode.name);
						dirData.list[k].sector = lastENode.sector;
						writeDisk(ATA0, &lastENode, sizeof(eNode), (refData.sector+refData.sectorCant-1), 
							  sizeof(unsigned int) + k*sizeof(eNode));
						return;
					}
				}
				
			}
		}
	}
	
	
	return;
	
}



/*Libera todos los sectores ocupados por "file"*/
void destroy_file(File * file){
	
	RefDataSector refDataSector;
	unsigned int currentSector = file->sectorRefData;
	readDisk(ATA0, &refDataSector, sizeof(RefDataSector), currentSector, 0);
	
	int dir=0;
	File_info fileInfo;
	finfo(file->sector,&fileInfo);
	if(fileInfo.type == DIRECTORY_TYPE) dir = 1;
	
	File hijo;
	DirData dirData;
	RefData refData;
	int i, j, k;
	for(i=0; (i < refDataSector.cant); i++){
		if(i == REF_DATA_CANT -1){
			clearSector(currentSector);	
			currentSector = refDataSector.next;
			readDisk(ATA0, &refDataSector, sizeof(RefDataSector), currentSector, 0);
			i=-1;
		}
		else{
			refData=refDataSector.list[i];
			for(j=0; j < refData.sectorCant; j++){	
				if(dir){
					readDisk(ATA0, &dirData, sizeof(DirData), refData.sector + j, 0);
					for(k=0; k<dirData.eNodeCant; k++){
						if((strcmp(dirData.list[k].name, ".") != 0)
							&& (strcmp(dirData.list[k].name, "..") != 0)){
							
							loadHeaderFromDisk(dirData.list[k].sector,&hijo);
							destroy_file(&hijo);
						}
					}
				}
				clearSector(refData.sector + j);			
			}
		}
	}
	
	clearSector(currentSector);
	clearSector(file->sector);
	saveTable();
	file->sector=-1;
	
}

/*Actualiza el path del directorio actual en relacion al path pasado como argumento*/
void refreshPath(char * path){
	
	char newPath[MAX_PATH];
	char cola[MAX_PATH];
	int isTheLastOne;
	int i;
	
	if(strcmp(path, "/")== 0){		
		strcpy(currentPath, "");
		return;
	}
	
	if(path[0] != '/'){		
		strcpy(newPath, currentPath);
	}else{
		newPath[0]='\0';
		path++;
	}
	do{	
		char first[FILE_NAME];
		getFirstNode(first, path);
		
		if(strcmp(first, ".") == 0){
	
		}else if(strcmp(first, "..") == 0){
			
			for(i = strlen(newPath)-1; i > 0 && newPath[i]!= '/';i--);
			strcpy(newPath+i, "\0");
		}else{
			strcpy(newPath+strlen(newPath), "/");
			strcpy(newPath+strlen(newPath),first);
		}
		
		isTheLastOne=isLastNode(path);
		getCola(cola, path);
		strcpy(path, cola);
		
	}while(!isTheLastOne);
	
	strcpy(currentPath, newPath);
	
	return;
}

/*Se setea el currectDir (fileTable[0]) con el archivo de la tabla de archivos con indice "index" y se actualiza el path*/
void changeCurrentDir(char * path, int index){
	fileTable[0]=fileTable[index];
}

/*Actualiza el inode ".." de file, setea en este el sector que se encuentra en file->psector*/
void changeParentSector(File * file){

	RefDataSector refDataSector;
	readDisk(ATA0, &refDataSector, sizeof(RefDataSector), file->sectorRefData, 0);
	
	DirData dirData;
	RefData refData;
	int i, j, k;
	for(i=0; i < refDataSector.cant; i++){
		if(i == REF_DATA_CANT -1){
			readDisk(ATA0, &refDataSector, sizeof(RefDataSector), refDataSector.next, 0);
			i=-1;
		}
		else{
			refData=refDataSector.list[i];
			for(j=0; j < refData.sectorCant; j++){
				readDisk(ATA0, &dirData, sizeof(DirData), refData.sector + j, 0);
				for(k=0; k<dirData.eNodeCant; k++){
					if(strcmp("..", dirData.list[k].name) == 0){
						dirData.list[k].sector=file->psector;
						writeDisk(ATA0, &dirData, sizeof(DirData), refData.sector + j, 0);
						return;
					}
				}
				
			}
		}
	}
}


/*Piso el header del Filse System*/
uint32_t sys_format(registers_t* regs){
  	writeDisk(ATA0, "formateado", 10, 10, 0);
  	return 0;
}

/*Crea un archivo vacio con nombre "name" y permisos "mode"*/
File * create_empty_file(char* name, int mode){
        
        File * parentDir;
        
        parentDir=getParentDir(name);

        if(parentDir == NULL){
		errno=ERR_UNEX;
                return NULL;
        }
        
        if(!hasPermission(parentDir, WRITE_PERMISSION)){
		errno= ERR_PERM;
                return NULL;
        }
        
        char newFileName[FILE_NAME];
        getLastNode(newFileName, name);
  
        File * newDir;
        
        newDir = getChild(parentDir, newFileName);

        if(newDir != NULL){
      		errno= ERR_FILEX;
                return NULL;
        }
        
        
        File* f=createFile(parentDir->sector, mode, FILE_TYPE);
        saveHeaderOnDisk(f,0);
        
        RefDataSector refDataSector;
        
        int new_dirData_sector=getFileFreeSector();
        
        FileData fileData;
        int i=0;
        for(i=0;i<SECTOR_SIZE-1;i++){
                fileData.data[i]='\0';
        }
        writeDisk(ATA0, &fileData, sizeof(FileData), new_dirData_sector, 0);
        
        refDataSector.cant=1;
        
        refDataSector.list[refDataSector.cant-1].sector=new_dirData_sector;
        refDataSector.list[refDataSector.cant-1].sectorCant=1;
        
        sys_add_enode(parentDir,newFileName,f->sector);
        
        writeDisk(ATA0, &refDataSector, sizeof(RefDataSector), f->sectorRefData, 0);
        
        return f;
}


/*Creo un FIFO con nombre "name" y permisos "mode"*/
int sys_mkfifo(char* name, int mode){

        File * parentDir;
        
        parentDir=getParentDir(name);

        if(parentDir == NULL){
		errno=ERR_UNEX;
                return -1;
        }
        
        if(!hasPermission(parentDir, WRITE_PERMISSION)){
		errno= ERR_PERM;
                return -1;
        }
        
        char newDirName[FILE_NAME];
        getLastNode(newDirName, name);
        
        if(strlen(newDirName) < 1){
     		errno=  ERR_NLEN;
                return -1;
        }
  
        File * newDir;
        
        newDir = getChild(parentDir, newDirName);

        if(newDir != NULL){
      		errno= ERR_FILEX;
                return -1;
        }
                
        File * file;

        file = createFile(parentDir->sector, mode, FIFO_TYPE);
        strcpy(file->name, name);

        sys_add_enode(parentDir, name, file->sector);
        
        return 0;
}

/*Creo un directorio con nombre "name" y permisos "mode" en el directoio "parent"*/
void makeDirectory(File * parent, char * name,int mode){
                        
                File * file = createFile(parent->sector, mode, DIRECTORY_TYPE);
                strcpy(file->name, name);
        
                sys_add_enode(parent, name, file->sector);
                                
                initDirData(file);
                
                return;
}


/*Crear un directorio con path "name" y permisos "mode"*/
int sys_mkdir(char* name,int mode){
        
        File * parentDir;
        
        parentDir=getParentDir(name);

        if(parentDir == NULL){
		errno=ERR_UNEX;
                return -1;
        }
        
        if(!hasPermission(parentDir, WRITE_PERMISSION)){
		errno= ERR_PERM;
                return -1;
        }
        
        char newDirName[FILE_NAME];
        getLastNode(newDirName, name);
        
        if(strlen(newDirName) < 1){
     		errno=  ERR_NLEN;
                return -1;
        }
  
        File * newDir;
        
        newDir = getChild(parentDir, newDirName);

        if(newDir != NULL){
      		errno= ERR_FILEX;
                return -1;
        }
                
        makeDirectory(parentDir, newDirName,mode);
        
        return 0;
}

/*Crea un archivo DIRECTORY, FIFO o FILE*/
uint32_t sys_mknode(registers_t* regs){

	switch(regs->edx){
		case DIRECTORY_TYPE:
			regs->eax=sys_mkdir((char*)regs->ebx,regs->ecx);
			break;
		case FIFO_TYPE:
			regs->eax=sys_mkfifo((char*)regs->ebx,regs->ecx);
			break;
		case FILE_TYPE:
			regs->eax=create_empty_file((char*)regs->ebx,regs->ecx)==NULL?-1:0;
			break;
	}
	 
	return 0;
}

/*Cambia el directorio actual*/
uint32_t sys_chdir(registers_t* regs){
		
	File * file;
	
	file = getFileByPath(currentDir, (char*)regs->ebx);
	
	/*Si no existe el archivo o no es de tipo directorio salgo*/
	if(file == NULL){
		errno=ERR_UNEX;
		regs->eax=-1;
		return 0;		
	}
	
	if(file->type != DIRECTORY_TYPE){
		errno=ERR_NOTDIR;
		regs->eax=-1;
		return 0;
	}
		
	/*Si no tengo permiso de ejecucion del directorio al que quiero entrar salgo*/
	if(!hasPermission(file, EXE_PERMISSION)){
		errno=ERR_PERM;
		regs->eax=-1;
		return 0;
	}
		
	changeCurrentDir((char*)regs->ebx, 1);
	refreshPath((char*)regs->ebx);

	return 0;
}

uint32_t sys_finfo(registers_t* regs){
		
	File_Disk file_Disk;
	readDisk(ATA0, &file_Disk, sizeof(File_Disk), regs->ebx, 0);
		
	((File_info*)regs->ecx)->type=file_Disk.type;
	((File_info*)regs->ecx)->mode=file_Disk.mode;
	
	strcpy(((File_info*)regs->ecx)->owner,file_Disk.owner);
	strcpy(((File_info*)regs->ecx)->group,file_Disk.group);
	
	return 0;
}

uint32_t sys_fcount(registers_t* regs){
	File origenFile;
	loadHeaderFromDisk(regs->ebx,&origenFile);
	origenFile.count+=regs->ecx;
	if(origenFile.count==0){
		destroy_file(&origenFile);
	}
	else{
		saveHeaderOnDisk(&origenFile, 0);
	}
	
	return 0;
}

uint32_t sys_setgName(registers_t* regs){
	strcpy(groupName,(char*)regs->ebx);
	printk(groupName);
	printk("\n");
	return 0;
}

uint32_t sys_setuName(registers_t* regs){
	strcpy(userName,(char*)regs->ebx);
	return 0;
}

uint32_t sys_chmod(registers_t* regs){
	
	File *file;
	file = getFileByPath(currentDir, (char*)regs->ebx);
	
	if(file==NULL){
		errno=ERR_UNEX;
		regs->eax=-1;
		return 0;
	}

	file->mode=regs->ecx;

	saveHeaderOnDisk(file, 0);
	return 0;
}

uint32_t sys_lchown(registers_t* regs){
	File *file;
	file = getFileByPath(currentDir, (char*)regs->ebx);
	
	if(file==NULL){
		errno=ERR_UNEX;
	
		regs->eax=-1;
		return 0;
	}
	
	strcpy(file->owner,(char*)regs->ecx);
	strcpy(file->group,(char*)regs->edx);

	saveHeaderOnDisk(file, 0);
	regs->eax=0;
	return 0;
}

int init_filesystem(){
	register_functionality(23,sys_setuName);
	register_functionality(46,sys_setgName);
	register_functionality(55,sys_finfo);
	register_functionality(56,sys_fcount);
	register_functionality(12,sys_chdir);
	register_functionality(14,sys_mknode);
	register_functionality(15,sys_chmod);
	register_functionality(16,sys_lchown);
	register_functionality(199,sys_format);
}

int loadFileSystem(){
	
		
        initSectorTable();

        char header[100];
	
        readDisk(ATA0, header, strlen(TABLE_HEADER), TABLE_STARTUP_SECTOR, 0);
        
        readDisk(ATA0, sectorsList, MAX_SECTOR_BYTES, TABLE_STARTUP_SECTOR, strlen(TABLE_HEADER));


	if(!strcmp(header,TABLE_HEADER)){
	  	printk("Cargando file system encontrado.\n");
                loadFileTable();
                return 0;
        }
        
		
	printk("No se ha encontrado un file system. Creando uno...\n");
	createFilesystem();
		
        return -1;
}
